home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
admin
/
linuxcon.000
/
linuxcon
/
linuxconf-1.6
/
translate
/
msgscan.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-04-14
|
8KB
|
381 lines
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include "../misc/misc.h"
#include "internal.h"
// This table indicates the correspondance for the first
// string and second string of the MSG_B macro.
static char *tblang;
#ifdef UNIX
#include <limits.h>
#define MAXIMUM_PATH PATH_MAX
#else
#define MAXIMUM_PATH 128
#endif
struct READINFO{
int noline;
char buf[1000];
FILE *fin;
};
/*
Print an error message in a popup
Stubs to avoid linking the world
*/
void xconf_error (const char *msg, ...)
{
va_list list;
va_start (list,msg);
vfprintf (stderr,msg,list);
va_end (list);
}
struct {
const char *fname;
int noline;
int nberr;
int showname;
int showline; // First error for a context
}err;
/*
Record basic info about errors
*/
static void msgscan_errset (const char *fname, int noline)
{
if (err.fname == NULL || strcmp(err.fname,fname)!=0){
err.showname = 1;
}
err.fname = fname;
err.noline = noline;
err.showline = 1;
}
/*
Display an error message with context
*/
static void msgscan_err (const char *ctl, ...)
{
va_list list;
va_start (list,ctl);
if (err.showname){
fprintf (stderr,"ERR: In file %s\n",err.fname);
err.showname = 0;
}
if (err.showline){
fprintf (stderr,"\t\tstarting on line %d\n",err.noline);
err.showline = 0;
}
fprintf (stderr,"\t\t\t");
vfprintf (stderr,ctl,list);
va_end (list);
}
static int msgscan_read (READINFO &inf, int signal_err)
{
int ret = fgets_cont (inf.buf,sizeof(inf.buf)-1,inf.fin);
inf.noline++;
if (ret == -1 && signal_err){
msgscan_err ("EOF while parsing\n");
}
return ret;
}
static char *scan_copyid (const char * pt, char id[])
{
pt = str_skip (pt);
char *ptid = id;
while (isalpha(*pt) || isdigit(*pt) || *pt == '_'){
*ptid++ = *pt++;
}
*ptid = '\0';
return (char*)pt;
}
static int scan_parseid (char * &pt, char id[])
{
int ret = -1;
pt = scan_copyid (pt,id);
if (id[0] != '\0'){
if (isdigit(id[0])){
msgscan_err ("Invalid id %s\n",id);
}else{
ret = 0;
}
}
return ret;
}
/*
Extract a single string from a C source.
*/
static int scan_parse1str (char * &pt, SSTRING &s)
{
int ret = -1;
pt = str_skip (pt);
if (*pt != '"'){
msgscan_err ("Expected an openning \"\n");
}else{
pt++;
char *start = pt;
while (1){
if (*pt == '\0'){
msgscan_err ("Expected an ending \"\n");
break;
}else if (*pt == '"'){
ret = 0;
*pt++ = '\0';
s.append (start);
break;
}else if (*pt == '\\'){
pt++;
if (*pt != '\0') pt++;
}else{
pt++;
}
}
}
return ret;
}
/*
Extract a string (or sequence) from a C source. A string may be made
of several strings concatenated and potentially spreaded on
several lines.
*/
static int scan_parsestr (
char * &pt,
SSTRING &s,
READINFO &inf)
{
int ret = -1;
s.setfrom ("");
while (1){
pt = str_skip (pt);
if (*pt == '\0'){
if (msgscan_read(inf,1)==-1){
break;
}
pt = inf.buf;
}else if (*pt != '"'){
if (ret == -1){
msgscan_err ("Expected an openning \"\n");
}
break;
}else if (scan_parse1str(pt,s)==-1){
ret = -1;
break;
}else{
// One string was seen, looking for others
ret = 0;
}
}
return ret;
}
/*
Parse a MSG_x() macro to extract the ID and the strings
Return the pointer after the closing parenthese.
*/
static char *scan_parse(
char *pt,
TR_STRINGS &tr,
READINFO &inf,
int nbsreq) // Number of strings expected
{
/* #Specification: translation / message / encoding in source
Messages are created in C (C++) source files and
extracted with a utility (msgscan). A message is
defined like this
#
// This is a message without translation
MSG_U(msgid,"message's text")
// This is a message with a proposed translation
MSG_B(msgid,"message's text","Texte du message")
#
msgid is a unique identifier generally composed of
letters and number. It must respected lexical
convention for macros (as it will be #defined)
*/
pt = str_skip (pt);
int last_nberr = err.nberr;
if (pt[0] == '('){
char id[100];
if (scan_parseid(++pt,id)!=-1){
SSTRING tbs[2];
int nbs = 0;
while (1){
pt = str_skip (pt);
if (pt[0] == '\0'){
// We must refill the buffer
if (msgscan_read (inf,1)==-1){
break;
}
pt = inf.buf;
}else if (*pt == ')'){
pt++;
break;
}else if (*pt != ','){
msgscan_err ("expected comma after id\n");
break;
}else if (nbs == nbsreq){
msgscan_err ("Too many strings\n");
break;
}else if (scan_parsestr(++pt,tbs[nbs],inf)==0){
nbs++;
}else{
break;
}
}
if (err.nberr == last_nberr){
if (nbs != nbsreq){
msgscan_err ("Not enough strings supplied\n");
}else{
TR_STRING *t = tr.getitem(id);
if (t == NULL){
t = new TR_STRING (id);
tr.add (t);
}
if (t->was_changed()){
msgscan_err ("Duplicate translation id %s\n"
,id);
const char *ori = t->getorigin();
msgscan_err (" It was defined in %s\n",ori);
msgscan_err (" Previous definition was \"%s\"\n"
,t->getmsg(tblang[0]));
msgscan_err (" New definition is \"%s\"\n",tbs[0].get());
}else{
t->setorigin (err.fname);
for (int i=0; i<nbs; i++){
t->settranslation (tblang[i]
,tbs[i].get());
}
}
}
}
}
}else{
msgscan_err("Expected (\n");
}
if (err.nberr != last_nberr){
// We skip this line to avoid falling always on the same
// error.
while (*pt != '\0') pt++;
}
return pt;
}
/*
Locate all messages in a source file and update the
dictionary.
Return -1 if any error
*/
int scan_one (const char *fname, TR_STRINGS &tr)
{
int ret = -1;
READINFO inf;
inf.noline = 0;
inf.fin = vfopen (fname,"r");
if (inf.fin == NULL){
fprintf (stderr,"Can't open file %s (%s)\n",fname
,strerror(errno));
}else{
ret = 0;
while (msgscan_read (inf,0)!=-1){
char *pt = inf.buf;
// Maybe more than one message on the line
while (1){
pt = strstr (pt,"MSG");
if (pt != NULL){
char verb[1000];
pt = scan_copyid (pt,verb);
if (strcmp(verb,"MSG_U")==0){
msgscan_errset (fname,inf.noline);
pt = scan_parse (pt,tr,inf,1);
}else if (strcmp(verb,"MSG_B")==0){
msgscan_errset (fname,inf.noline);
pt = scan_parse (pt,tr,inf,2);
}
}else{
break;
}
}
}
}
return ret;
}
#if 0
int scan_vone (const char *fname, TR_STRINGS &tr)
{
int ret = 0;
char *tb[1000];
int nb = vdir_getlistp (fname,tb,1000);
for (int i=0; i<nb; i++){
ret |= scan_one (tb[i],tr);
}
return ret;
}
#endif
static void usage()
{
fprintf (stderr,
"msgscan 1.0\n"
"msgscan sysname dictionary header lang_letters source source ...\n"
"\n"
"Update the dictionary file with source (C C++ source)\n"
"The file dictionary will be the ascii dictionary\n"
"the file \"header\" will be produced\n"
"and must be included in every source files using the dictionary\n"
"\n"
"lang_letters is a string of 2 letters use to tag the first and\n"
"second string extracted from an MSG_U/MSG_B macro\n"
"\n"
"Normal usage for the linuxconf project\n"
"\tmsgscan netconf ../messages/sources/netconf.dic netconf.m EF *.c\n"
);
}
int main (int argc, char *argv[])
{
int ret = -1;
if (argc < 6){
usage();
}else{
TR_STRINGS tr;
const char *sys = argv[1];
const char *pathdict = argv[2];
const char *pathincl = argv[3];
tblang = argv[4];
tr.read (pathdict);
tr.deltranslation (tblang[0]);
tr.deltranslation (tblang[1]);
ret = 0;
for (int i=5; i<argc; i++){
ret |= scan_one (argv[i],tr);
}
if (ret == 0){
char path[MAXIMUM_PATH];
sprintf (path,"%s.old",pathdict);
rename (pathdict,path);
tr.write (pathdict);
tr.writeh (sys,pathincl);
tr.showold (tblang[0]);
}
}
return ret;
}